KeyMappingApplier.java
package org.codefilarete.stalactite.engine.configurer.dslresolver;
import org.codefilarete.stalactite.engine.configurer.model.IdentifierMapping;
import org.codefilarete.stalactite.engine.configurer.dslresolver.InheritanceConfigurationResolver.ResolvedConfiguration;
import org.codefilarete.stalactite.sql.ConnectionConfiguration;
import org.codefilarete.stalactite.sql.Dialect;
import org.codefilarete.stalactite.sql.ddl.structure.Table;
import org.codefilarete.tool.collection.Iterables;
import org.codefilarete.tool.collection.KeepOrderSet;
import static org.codefilarete.tool.collection.Iterables.first;
public class KeyMappingApplier<C, I> {
private final Dialect dialect;
private final ConnectionConfiguration connectionConfiguration;
public KeyMappingApplier(Dialect dialect, ConnectionConfiguration connectionConfiguration) {
this.dialect = dialect;
this.connectionConfiguration = connectionConfiguration;
}
/**
* Fills in {@link ResolvedConfiguration#setIdentifierMapping(IdentifierMapping)} on all the given configurations.
* This ensures that for each configuration, the identifier mapping is set.
* The logic takes the key mapping defined by the highest (and only) identifier policy and applies it to the very
* first entity of the path. Then, for each entity on the path, it creates a primary key and a foreign key as well
* as a default identifier mapping that takes the initial one as a source.
*
* @param bottomToTopConfigurations the configurations to process, ordered from bottom to top
*/
void resolve(KeepOrderSet<ResolvedConfiguration<?, I>> bottomToTopConfigurations) {
boolean firstTableChange = true;
ResolvedConfiguration<?, I> keyDefiner = null;
AssignedByAnotherIdentifierMapping<?, I> assignedByAnotherIdentifierMapping;
Iterable<ResolvedConfiguration<?, I>> topToBottomConfigurations = () -> Iterables.reverseIterator(bottomToTopConfigurations.getDelegate());
ResolvedConfiguration<?, I> previousConfiguration = first(topToBottomConfigurations);
Table previousTable = previousConfiguration.getTable();
for (ResolvedConfiguration<?, I> resolvedConfiguration : topToBottomConfigurations) {
if (resolvedConfiguration.getKeyMapping() != null) {
// we keep the definer for "later": at time when we detect table change to better match table change logic
keyDefiner = resolvedConfiguration;
}
if (previousTable != resolvedConfiguration.getTable()) {
if (firstTableChange) {
// very first "entity" on the path, so it takes the identifier manager
PrimaryKeyResolver<C, I> keyStep = new PrimaryKeyResolver<>();
keyStep.addIdentifyingPrimarykey(keyDefiner.getKeyMapping(),
// Note that primary key must be created on previous table
previousTable,
dialect.getColumnBinderRegistry(),
resolvedConfiguration.getNamingConfiguration().getColumnNamingStrategy(),
resolvedConfiguration.getNamingConfiguration().getUniqueConstraintNamingStrategy());
// we have a table change, so we need to propagate the primary key
PrimaryKeyPropagator primaryKeyPropagator = new PrimaryKeyPropagator<>();
primaryKeyPropagator.propagate(previousTable.<I>getPrimaryKey(),
resolvedConfiguration.getTable(),
resolvedConfiguration.getNamingConfiguration().getForeignKeyNamingStrategy());
// setting identifier mapping, this must be done after primary key creation because some
// identifier managers require them to be set
IdentifierMappingBuilder<?, I> identifierMappingBuilder = new IdentifierMappingBuilder<>(keyDefiner.getMappingConfiguration(), keyDefiner, dialect, connectionConfiguration);
IdentifierMapping<?, I> identifierMapping = identifierMappingBuilder.build();
previousConfiguration.setIdentifierMapping(identifierMapping);
assignedByAnotherIdentifierMapping = new AssignedByAnotherIdentifierMapping(identifierMapping);
resolvedConfiguration.setIdentifierMapping(assignedByAnotherIdentifierMapping);
firstTableChange = false;
}
}
previousTable = resolvedConfiguration.getTable();
previousConfiguration = resolvedConfiguration;
}
// algorithm above doesn't take into account the straight inheritance without table change, here's below
// what fixes it.
ResolvedConfiguration<?, I> bottomResolvedConfiguration = first(bottomToTopConfigurations);
if (firstTableChange) {
// very first "entity" on the path, so it takes the identifier manager
PrimaryKeyResolver<C, I> keyStep = new PrimaryKeyResolver<>();
keyStep.addIdentifyingPrimarykey(keyDefiner.getKeyMapping(),
bottomResolvedConfiguration.getTable(),
dialect.getColumnBinderRegistry(),
bottomResolvedConfiguration.getNamingConfiguration().getColumnNamingStrategy(),
bottomResolvedConfiguration.getNamingConfiguration().getUniqueConstraintNamingStrategy());
IdentifierMappingBuilder<?, I> identifierMappingBuilder = new IdentifierMappingBuilder<>(
keyDefiner.getMappingConfiguration(),
bottomResolvedConfiguration,
dialect,
connectionConfiguration);
IdentifierMapping<?, I> identifierMapping = identifierMappingBuilder.build();
bottomResolvedConfiguration.setIdentifierMapping(identifierMapping);
}
}
}